package per.jdz.service.impl;

import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.MailException;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import per.jdz.entity.auth.Account;
import per.jdz.mapper.UserMapper;
import per.jdz.service.AuthorizeService;

import java.util.Optional;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * ClassName: AuthorizeService
 * Description: 自定义类实现用户详情服务接口
 *
 * @Author: jdz
 * @Create: 2023/4/19 - 15:48
 */

@Service
public class AuthorizeServiceImpl implements AuthorizeService {

    @Value("${spring.mail.username}")
    String from;

    @Resource
    private UserMapper mapper;
    @Resource
    MailSender mailSender;

    @Resource
    StringRedisTemplate template;
    BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if (username == null) {
            throw new UsernameNotFoundException("用户名不能为空");
        }
        final Account account = mapper.findAccountByNameOrEmail(username);
        if (account == null) {
            throw new UsernameNotFoundException("用户名或密码错误!");
        }
        return User
                .withUsername(account.getUsername())
                .password(account.getPassword()) // 已经加密后的密码了
                .roles("user")//角色的前面加上ROLE student就变成了权限
                .build();
    }
    /**
     * 1. 先生成对应的验证码
     * 2. 发送验证码到指定邮箱
     * 3. 如果发送失败，
     * 4. 如果发送成功， 把邮箱和对应的验证码直接放到Redis里面
     *      * （过期时间3分钟，如果此时重新要求发邮件，
     *      * 那么，只要剩余时间低于2分钟，就可以重新发送一次，重复此流程）
     * 5. 用户在注册时，再从Redis里面取出对应键值对，然后看验证码是否一致
     */
    @Override
    public String sendValidateEmail(String email, String sessionId, boolean hasAccount) {
        String key = "email:" + sessionId + ":" + email + ":" + hasAccount;
        if (Boolean.TRUE.equals(template.hasKey(key))) {
            final Long expire = Optional.ofNullable(template.getExpire(key, TimeUnit.SECONDS)).orElse(0L);
            if (expire > 120) {
                return "请60秒后再发送！";
            }
        }
        final Account account = mapper.findAccountByNameOrEmail(email);
        if (hasAccount && account == null) {
            return "没有此邮件地址的账户";
        }
        if (!hasAccount && account != null) {
            return "此邮箱已被注册！";
        }
        final Random random = new Random();
        int code = random.nextInt(899999) + 100000;
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(from + "@163.com");
        message.setTo(email);
        message.setSubject("您的验证邮件");
        message.setText("验证码是：" + code);
        try {
            mailSender.send(message);
            template.opsForValue().set(key, String.valueOf(code), 3, TimeUnit.MINUTES);
            return null;
        } catch (MailException e) {
            e.printStackTrace();
            return "邮件发送失败，请检查邮箱地址是否有效~";
        }
    }

    @Override
    public String validateAndRegister(String username, String password, String email, String code, String sessionId) {
        String key = "email:" + sessionId + ":" + email+ ":false";
        if (Boolean.TRUE.equals(template.hasKey(key))) {
            final String authCode = template.opsForValue().get(key);
            if (authCode == null) {
                return "验证码失效了，请重新请求~";
            } else if (authCode.equals(code)) {
                final Account account = mapper.findAccountByNameOrEmail(username);
                if (account != null) {
                    return "用户名已被注册，请换个名字~";
                }
                password = encoder.encode(password);
                template.delete(key);
                if (mapper.CreateAccount(username, password, email) > 0) {
                    return null;
                } else {
                    return "内部错误，请联系管理员!";
                }
            } else {
                return "验证码错误，请检查后提交";
            }
        } else {
            return "请先请求一封验证码邮件";
        }
    }

    @Override
    public String validateOnly(String email, String code, String sessionId) {
        String key = "email:" + sessionId + ":" + email+ ":true";
        if (Boolean.TRUE.equals(template.hasKey(key))) {
            final String authCode = template.opsForValue().get(key);
            if (authCode == null) {
                return "验证码失效了，请重新请求~";
            } else if (authCode.equals(code)) {
                template.delete(key);
                return null;
            } else {
                return "验证码错误，请检查后提交";
            }
        } else {
            return "请先请求一封验证码邮件";
        }
    }

    @Override
    public boolean resetPassword(String password, String email) {
        password = encoder.encode(password);
        return mapper.resetPasswordByEmail(password, email) > 0;
    }
}
